package com.network.retrofit.net;

import com.network.retrofit.net.callback.DownloadCallBack;
import com.network.retrofit.utils.NetWorkLogUtil;
import com.trello.rxlifecycle3.LifecycleTransformer;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.HashMap;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * 项目: com.network.retrofit.net
 * 创建人: LuoFG
 * 创建时间: 2021/7/2  14:47
 * 描述:
 */
public class RetrofitFileClient {

    private static class InstanceHolder {
        private static RetrofitFileClient instance = new RetrofitFileClient();
    }

    private static RetrofitFileClient getInstance() {
        return RetrofitFileClient.InstanceHolder.instance;
    }

    public static RetrofitFileClient getService() {
        return getInstance();
    }

    public static final long TOTAL_ERROR = -1;//获取进度失败
    private HashMap<String, Disposable> downCalls;//用来存放各个下载的请求

    public void init() {

    }


    /**
     * @param url         请求地址
     * @param filePath    文件保存路径
     * @param isInterrupt 是否支持断点续传
     */
    public void downFile(String url, String filePath, String fileName, LifecycleTransformer lifecycleTransformer, boolean isInterrupt,DownloadCallBack downloadCallBack) {
        if (getDownCalls().containsKey(url) && getDownCalls().get(url).isDisposed()) {
            NetWorkLogUtil.logE("已经在下载了，不要重复请求，url", url);
            return;
        }

        //创建文件夹
        createPath(filePath);

        if (isInterrupt) {
            File file = new File(filePath, fileName);
            startInterruptDown(url, file,lifecycleTransformer);
        } else {
            startDown(url, filePath, fileName,lifecycleTransformer);
        }


    }


    /**
     * 暂停方法
     *
     * @param url
     */
    public void pauseDown(String url) {
        if (getDownCalls().containsKey(url)) {
            getDownCalls().get(url).dispose();//取消订阅
        }
    }

    /**
     * 不支持断点续传，删除回炉重来
     *
     * @param url
     * @param filePath
     * @param fileName
     */
    private void startDown(String url, String filePath, String fileName, LifecycleTransformer lifecycleTransformer) {
        deleteFile(filePath, fileName);
        //准备开始下载
        final long totalLength = getContentLength(url);

        RetrofitClient.getService().instanceRetrofitGson(RetrofitBaseApi.class)
                .doDownFile(url)
                .compose(RetrofitClient.rxConfigFileDown(null))
                .subscribe(new Observer<ResponseBody>() {
                    @Override
                    public void onSubscribe(@NotNull Disposable d) {
                        getDownCalls().put(url, d);
                    }

                    @Override
                    public void onNext(@NotNull ResponseBody responseBody) {
                        RandomAccessFile randomAccessFile = null;
                        InputStream inputStream = null;
                        long totalDown = totalLength;//下载总长度
                        long progressLength = 0;//目前的长度
                        long responseLength = 0;//相应文件的长度
                        File file = new File(filePath, fileName);
                        try {
                            byte[] buf = new byte[2048];
                            int len = 0;
                            responseLength = responseBody.contentLength();//剩余的文件长度
                            inputStream = responseBody.byteStream();
                            randomAccessFile = new RandomAccessFile(file, "rwd");//设置读写模式
                            if (progressLength == 0) {
                                randomAccessFile.setLength(responseLength);//如果还未开始下载，则创建一个完整长度的文件
                            }
                            randomAccessFile.seek(progressLength);//将文件指针定位到pos位置

                            int progress = 0;
                            int lastProgress = 0;

                            while ((len = inputStream.read(buf)) != -1) {
                                randomAccessFile.write(buf, 0, len);
                                progressLength += len;
                                lastProgress = progress;
                                progress = (int) (progressLength * 100 / totalDown);
                                if (progress > 0&&progress != lastProgress ) {
                                    NetWorkLogUtil.logE(url, "下载百分比" + progress);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            NetWorkLogUtil.logE("onNext" + url, e.toString());
                        } finally {
                            try {
                                if (randomAccessFile != null) {
                                    randomAccessFile.close();
                                }

                                if (inputStream != null) {
                                    inputStream.close();
                                }

                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }
                    }

                    @Override
                    public void onError(@NotNull Throwable e) {
                        NetWorkLogUtil.logE("onError" + url, e.toString());
                        getDownCalls().remove(url);
                        deleteFile(filePath, fileName);
                    }

                    @Override
                    public void onComplete() {
                        getDownCalls().remove(url);
                        NetWorkLogUtil.logE("onComplete" + url, "下载完成");
                    }
                });
    }


    /**
     * 启动一个可支持断点续传的下载
     *
     * @param url
     * @param file
     */
    private void startInterruptDown(String url, File file, LifecycleTransformer lifecycleTransformer) {
        final long totalLength = getContentLength(url);
        long progressLength = 0;
        if (file.exists()) {
            progressLength = file.length();
        }
        if(totalLength==progressLength){
            NetWorkLogUtil.logE("文件已存在无需下载");
            return;
        }

        //确定下载的范围,添加此头,则服务器就可以跳过已经下载好的部分
        String rang = "bytes=" + progressLength + "-" + totalLength;
        NetWorkLogUtil.logE("rang", rang);
        NetWorkLogUtil.logE("progress", (int) (progressLength / totalLength));
        NetWorkLogUtil.logE("------wait down-------");

        RetrofitClient.getService().instanceRetrofitGson(RetrofitBaseApi.class)
                .doDownFile(url, rang)
                .compose(RetrofitClient.rxConfigFileDown(lifecycleTransformer))
                .subscribe(new Observer<ResponseBody>() {
                    @Override
                    public void onSubscribe(@NotNull Disposable d) {
                        getDownCalls().put(url, d);
                    }

                    @Override
                    public void onNext(@NotNull ResponseBody responseBody) {
                        RandomAccessFile randomAccessFile = null;
                        InputStream inputStream = null;
                        long totalDown = totalLength;//下载总长度
                        long progressLength = 0;//目前的长度
                        if (file.exists()) {
                            progressLength = file.length();
                        }
                        try {
                            byte[] buf = new byte[2048];
                            int len = 0;
                            inputStream = responseBody.byteStream();

                            randomAccessFile = new RandomAccessFile(file, "rwd");//设置读写模式
                            randomAccessFile.seek(progressLength);//将文件指针定位到pos位置

                            int progress = 0;
                            int lastProgress = 0;

                            while ((len = inputStream.read(buf)) != -1) {
                                randomAccessFile.write(buf, 0, len);
                                progressLength += len;
                                lastProgress = progress;
                                progress = (int) (progressLength * 100 / totalDown);
                                if (progress > 0&&progress != lastProgress ) {
                                    NetWorkLogUtil.logE(url, "下载百分比" + progress);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                            NetWorkLogUtil.logE("onNext" + url, e.toString());
                            getDownCalls().remove(url);
                        } finally {
                            try {
                                if (randomAccessFile != null) {
                                    randomAccessFile.close();
                                }

                                if (inputStream != null) {
                                    inputStream.close();
                                }

                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                        }
                    }

                    @Override
                    public void onError(@NotNull Throwable e) {
                        NetWorkLogUtil.logE("onError" + url, e.toString());
                        getDownCalls().remove(url);
                    }

                    @Override
                    public void onComplete() {
                        getDownCalls().remove(url);
                        NetWorkLogUtil.logE("onComplete" + url, "下载完成");
                    }
                });
    }


    /**
     * 获取下载长度
     *
     * @param downloadUrl
     * @return
     */
    private long getContentLength(String downloadUrl) {
        Request request = new Request.Builder()
                .url(downloadUrl)
                .build();
        try {
            Response response = new OkHttpClient.Builder().build().newCall(request).execute();
            if (response != null && response.isSuccessful()) {
                long contentLength = response.body().contentLength();
                response.close();
                //NetWorkLogUtil.logE("contentLength",String.valueOf(contentLength));
                return contentLength == 0 ? TOTAL_ERROR : contentLength;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return TOTAL_ERROR;
    }

    /**
     * 删除文件
     *
     * @param filePath
     * @param fileName
     */
    private void deleteFile(String filePath, String fileName) {
        File fileBase = new File(filePath, fileName);
        if (fileBase.exists()) {
            fileBase.delete();
        }
    }

    /**
     * 创建文件夹*
     */
    public static final void createPath(String strPath) {

        try {
            File fileName = new File(strPath);
            if (fileName.exists() == false) {
                try {
                    fileName.mkdirs();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public HashMap<String, Disposable> getDownCalls() {
        if (downCalls == null) {
            downCalls = new HashMap<>();
        }
        return downCalls;
    }

}
